﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;

#endif
namespace com.susi.util.toolkit {
    //#if ODIN_INSPECTOR
    //    [LabelText("带事件列表"),ShowInInspector]
    //#endif
    /// <summary>
    /// 对List追加一层包装，以便于触发事件
    /// <br>当此对象<see cref="EventCollection{T}.IsDisposed"/>后，不能再对被包装的List进行操作</br>
    /// </summary>
    public class EventCollection<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, ICollection, IDisposable, IDisposaEventer, IDisposaEventer<EventCollection<T>> 
    {
      
#if ODIN_INSPECTOR
        [ShowInInspector, ShowIf("IsDisposed")]
#endif
        public bool IsDisposed { get; private set; }

        /// <summary>
        /// 对表进行一层包装。<see cref="InnerCollection"/>
        /// </summary>
        /// <param name="value"></param>
        public EventCollection(ICollection<T> value)
        {
            this.InnerCollection = value ?? throw new ArgumentNullException(nameof(value));
        }

        public EventCollection() : this(new List<T>()) { }

        public readonly ICollection<T> InnerCollection; /*{ get; private set; }*/

        /// <summary>
        /// 当Dispose和Clear的时候最多只触发1次
        /// </summary>
        public event Action onChangedEvent;

        /// <summary>
        /// 总是保证触发
        /// </summary>
        public event Action<T> onAddedEvent;

        /// <summary>
        /// 总是保证触发
        /// </summary>
        public event Action<T> onRemovedEvent;

        /// <summary>
        /// args=item 返回false的时候终止Add操作
        /// </summary>
        public event Func<T, bool> onAddingFlitters;

        /// <summary>
        /// args=item 返回false的时候终止操作
        /// <br>Clear和Dispose的时候会忽略Flitter</br>
        /// </summary>
        public event Func<T, bool> onRemovingFlitters;

        public event Action                     onDisposingEvent;
        public event Action<EventCollection<T>> onDisposingTEvent;

        public int Count => InnerCollection.Count;

        public bool IsReadOnly => InnerCollection.IsReadOnly;

        public bool IsSynchronized => ((ICollection) InnerCollection).IsSynchronized;

        public object SyncRoot => ((ICollection) InnerCollection).SyncRoot;

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和<see cref="onChangedEvent"/>
        /// </summary>
        public void Add(T item)
        {
            if (IsDisposed || !IsCrossAddingFliter(item)) return;
            InnerCollection.Add(item);
            onAddedEvent?.Invoke(item);
            onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和最多1次<see cref="onChangedEvent"/>
        /// </summary>
        public void AddRange(IEnumerable<T> ts)
        {
            if (IsDisposed || ts == null) return;
            bool ischanged = false;
            foreach (var item in ts) {
                if (!IsCrossAddingFliter(item)) continue;
                InnerCollection.Add(item);
                onAddedEvent?.Invoke(item);
                ischanged = true;
            }

            if (ischanged) onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 无视Fliter进行清空
        /// 最多只触发一次onChang
        /// </summary>
        public void Clear()
        {
            var copy = InnerCollection.ToArray();
            InnerCollection.Clear();
            foreach (var item in copy) {
                onRemovedEvent?.Invoke(item);
            }

            if (copy.Length != 0) onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 清空所有可移除项目
        /// </summary>
        public void ClearWithFliter()
        {
            var  copy     = InnerCollection.ToArray();
            bool isChange = false;
            foreach (var item in copy) {
                if (!IsCrossRemovingFliter(item)) continue;
                InnerCollection.Remove(item);
                onRemovedEvent?.Invoke(item);
                if (!isChange) isChange = true;
            }

            if (isChange) onChangedEvent?.Invoke();
        }

        public bool Contains(T item)
        {
            return InnerCollection.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            InnerCollection.CopyTo(array, arrayIndex);
        }

        public IEnumerator<T> GetEnumerator()
        {
            return InnerCollection.GetEnumerator();
        }

        /// <summary>
        /// 不通过或同时触发<see cref="onRemovedEvent"/>、<see cref="onChangedEvent"/>
        /// </summary>
        public bool Remove(T item)
        {
            if (!IsCrossRemovingFliter(item)) return false;
            var res = InnerCollection.Remove(item);
            if (res) {
                onRemovedEvent?.Invoke(item);
                onChangedEvent?.Invoke();
            }

            return res;
        }

        /// <summary>
        /// 没有移除任何元素返回false，否则返回true
        /// </summary>
        public bool RemoveRange(IEnumerable<T> ts)
        {
            if (IsDisposed && ts == null) return false;
            bool ischange = false;
            foreach (var item in ts) {
                if (!IsCrossRemovingFliter(item)) continue;
                var res = InnerCollection.Remove(item);
                if (res) {
                    onRemovedEvent?.Invoke(item);
                    if (!ischange) ischange = true;
                }
            }

            if (ischange) onChangedEvent?.Invoke();
            return ischange;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return InnerCollection.GetEnumerator();
        }

        private bool IsCrossAddingFliter(T item)
        {
            if (onAddingFlitters == null) return true;
            // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
            foreach (Func<T, bool> func in onAddingFlitters.GetInvocationList()) {
                if (func(item) == false) return false;
            }

            return true;
        }

        private bool IsCrossRemovingFliter(T item)
        {
            if (onRemovingFlitters == null) return true;
            // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
            foreach (Func<T, bool> func in onRemovingFlitters.GetInvocationList()) {
                if (func(item) == false) return false;
            }

            return true;
        }

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和<see cref="onChangedEvent"/>
        /// </summary>
        public int Add(object value)
        {
            if (!IsDisposed && !IsCrossAddingFliter((T) value)) return -1;
            var res = ((IList) this.InnerCollection).Add(value);
            if (res != -1) {
                onAddedEvent?.Invoke((T) value);
                onChangedEvent?.Invoke();
            }

            return res;
        }


        /// <summary>
        /// 等同<see cref="Remove(T)"/>
        /// </summary>
        public void Remove(object value)
        {
            this.Remove((T) value);
        }

        public void CopyTo(Array array, int index)
        {
            ((ICollection) InnerCollection).CopyTo(array, index);
        }

        /// <summary>
        /// 会调用一次<see cref="Clear"/>
        /// <para>即可能会触发多次<see cref="onRemovedEvent"/>和至多触发一次<see cref="onChangedEvent"/></para>
        /// <para>不会对里表和里表的所有元素执行Dispose，需要在DisposeEvent进行操作</para>
        /// </summary>
        public void Dispose()
        {
            if (IsDisposed) return;
            IsDisposed = true;
            onDisposingEvent?.Invoke();
            onDisposingTEvent?.Invoke(this);
            onDisposingEvent  = null;
            onDisposingTEvent = null;
            Clear();
            onAddingFlitters        = null;
            onRemovingFlitters = null;
            onAddedEvent          = null;
            onRemovedEvent        = null;
            onChangedEvent        = null;
        }
    }
}